-- WIDECHR.A
--
--                             Grant of Unlimited Rights
--
--     Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687,
--     F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained 
--     unlimited rights in the software and documentation contained herein.
--     Unlimited rights are defined in DFAR 252.227-7013(a)(19).  By making 
--     this public release, the Government intends to confer upon all 
--     recipients unlimited rights  equal to those held by the Government.  
--     These rights include rights to use, duplicate, release or disclose the 
--     released technical data and computer software in whole or in part, in 
--     any manner and for any purpose whatsoever, and to have or permit others 
--     to do so.
--
--                                    DISCLAIMER
--
--     ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR
--     DISCLOSED ARE AS IS.  THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED 
--     WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE
--     SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE 
--     OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A
--     PARTICULAR PURPOSE OF SAID MATERIAL.
--*
--
-- DESCRIPTION:
--
--      This program reads C250001.AW and C250002.AW; translates a special
--      character sequence into characters and wide characters with positions
--      above ASCII.DEL.  The resulting tests are written as C250001.A and
--      C250002.A respectively.   This program may need to
--      be modified if the Wide_Character representation recognized by
--      your compiler differs from the Wide_Character
--      representation generated by the package Ada.Wide_Text_IO.
--      Modify this program as needed to translate that file.
--
--      A wide character is represented by an 8 character sequence:
--
--          ["abcd"]
--
--      where the character code represented is specified by four hexadecimal
--      digits, abcd, with letters in upper case. For example the wide
--      character with the code 16#AB13# is represented by the eight
--      character sequence:
--
--          ["AB13"]
--
-- ASSUMPTIONS:
--
--      The path for these files is specified in ImpDef.
--
-- SPECIAL REQUIREMENTS:
--
--     Compile, bind and execute this program.  It will process the ".AW"
--     tests, "translating" them to ".A" tests.
--
-- CHANGE HISTORY:
--      11 DEC 96   SAIC   ACVC 2.1 Release
--
--      11 DEC 96   Keith  Constructed initial release version
--!

with Ada.Text_IO;
with Ada.Wide_Text_IO;
with Ada.Strings.Fixed;
with Impdef;

procedure WideChr is

  -- Debug
  --
  -- To have the program generate trace/debugging information, de-comment
  -- the call to Put_Line

  procedure Debug( S: String ) is
  begin
    null; -- Ada.Text_IO.Put_Line(S);
  end Debug;

  package TIO renames Ada.Text_IO;
  package WIO renames Ada.Wide_Text_IO;
  package SF renames Ada.Strings.Fixed;

  In_File : TIO.File_Type;

  -- This program is actually dual-purpose.  It translates the ["xxxx"]
  -- notation to Wide_Character, as well as a similar notation ["xx"] into
  -- Character.  The intent of the latter being the ability to represent
  -- literals in the Latin-1 character set that have position numbers
  -- greater than ASCII.DEL.  The variable Output_Mode drives the algorithms
  -- to generate Wide_Character output (Wide) or Character output (Narrow).

  type Output_Modes is ( Wide, Narrow );
  Output_Mode : Output_Modes := Wide;

  Wide_Out   : WIO.File_Type;
  Narrow_Out : TIO.File_Type;

  In_Line   : String(1..132); -- SB: $MAX_LINE_LENGTH

  -- Index variables
  -- 
  -- the following index variables: In_Length, Front, Open_Bracket and
  -- Close_Bracket are used by the scanning software to keep track of
  -- what's where.
  --
  -- In_Length stores the value returned by Ada.Text_IO.Get_Line indicating
  -- the position of the last "useful" character in the string In_Line.
  --
  -- Front retains the index of the first non-translating character in
  -- In_Line, it is used to indicate the starting index of the portion of
  -- the string to save without special interpretation.  In the example
  -- below, where there are two consecutive characters to translate, we see
  -- that Front will assume three different values processing the string,
  -- these are indicated by the digits '1', '2' & '3' in the comment
  -- attached to the declaration.  The processing software will dump
  -- In_Line(Front..Open_Bracket-1) to the output stream.  Note that in
  -- the second case, this results in a null string, and in the third case,
  -- where Open_Bracket does not obtain a third value, the slice
  -- In_Line(Front..In_Length) is used instead.
  --
  -- Open_Bracket and Close_Bracket are used to retain the starting index
  -- of the character pairs [" and "] respectively.  For the purposes of
  -- this software the character pairs are what are considered to be the
  -- "brackets" enclosing the hexadecimal values to be translated.
  --  Looking at the example below you will see where these index variables
  -- will "point" in the first and second case.

  In_Length     : Natural := 0;  --->  Some_["0A12"]["0B13"]_Thing
  Front         : Natural := 0;  --  1              2       3
  Open_Bracket  : Natural := 0;  --         1       2
  Close_Bracket : Natural := 0;  --               1       2

  -- Xlation
  --
  -- This translation table gives an easy way to translate the "decimal"
  -- value of a hex digit (as represented by a Latin-1 character)

  type Xlate is array(Character range '0'..'F') of Natural;
  Xlation : constant Xlate :=
            ('0' =>  0, '1' =>  1, '2' =>  2, '3' =>  3, '4' =>  4,
             '5' =>  5, '6' =>  6, '7' =>  7, '8' =>  8, '9' =>  9,
             'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14,
             'F' => 15,
             others => 0);

  -- To_Ch
  --
  -- This function takes a string which is assumed to be trimmed to just a
  -- hexadecimal representation of a Latin-1 character.  The result of the
  -- function is the Latin-1 character at the position designated by the
  -- incoming hexadecimal value.  (hexadecimal in human readable form)

  function To_Ch( S:String ) return Character is
    Numerical : Natural := 0;
  begin
    Debug("To Wide: " & S);
    for I in S'Range loop
      Numerical := Numerical * 16 + Xlation(S(I));
    end loop;
    return Character'Val(Numerical);
  exception
    when Constraint_Error => return '_';
  end To_Ch;

  -- To_Wide
  --
  -- This function takes a string which is assumed to be trimmed to just a
  -- hexadecimal representation of a Wide_character.  The result of the
  -- function is the Wide_character at the position designated by the
  -- incoming hexadecimal value.  (hexadecimal in human readable form)

  function To_Wide( S:String ) return Wide_character is
    Numerical : Natural := 0;
  begin
    Debug("To Wide: " & S);
    for I in S'Range loop
      Numerical := Numerical * 16 + Xlation(S(I));
    end loop;
    return Wide_Character'Val(Numerical);
  exception
    when Constraint_Error => return '_';
  end To_Wide;

  -- Make_Wide
  --
  -- this function converts a String to a Wide_String

  function Make_Wide( S: String ) return Wide_String is
    W: Wide_String(S'Range);
  begin
    for I in S'Range loop
      W(I) := Wide_Character'Val( Character'Pos(S(I)) );
    end loop;
    return W;
  end Make_Wide;

  -- Close_Files
  --
  -- Depending on which input we've processed, close the output file

  procedure Close_Files is
  begin
    TIO.Close(In_File);
    if Output_Mode = Wide then
      WIO.Close(Wide_Out);
    else
      TIO.Close(Narrow_Out);
    end if;
  end Close_Files;

  -- Process
  --
  -- for all lines in the input file
  --   scan the file for occurrences of [" and "]
  --     for found occurrence, attempt translation of the characters found
  --     between the brackets.  As a safeguard, unrecognizable character
  --     sequences will be replaced with the underscore character.  This
  --     handles the cases in the tests where the test documentation includes
  --     examples that are non-conformant: i.e. ["abcd"] or ["XXXX"]

  procedure Process( Input_File_Name: String ) is
  begin
    TIO.Open(In_File,TIO.In_File,Input_File_Name & ".aw" );

    if Output_Mode = Wide then
      WIO.Create(Wide_Out,WIO.Out_File, Input_File_Name & ".a" );
    else
      TIO.Create(Narrow_Out,TIO.Out_File, Input_File_Name & ".a" );
    end if;

    File: while not TIO.End_Of_File( In_File ) loop
      In_Line := (others => ' ');
      TIO.Get_Line(In_File,In_Line,In_Length);
      Debug(In_Line(1..In_Length));

      Front := 1;

      Line: loop
	     -- scan for next occurrence of ["abcd"]
	     Open_Bracket := SF.Index( In_Line(Front..In_Length), "[""" );
	     Close_Bracket := SF.Index( In_Line(Front..In_Length), """]" );
	     Debug( "[=" & Natural'Image(Open_Bracket) );
	     Debug( "]=" & Natural'Image(Close_Bracket) );

	     if Open_Bracket = 0 or Close_Bracket = 0 then
        -- done with the line, output remaining characters and exit
	       Debug("Done with line");
	       if Output_Mode = Wide then
	         WIO.Put_Line(Wide_Out, Make_Wide(In_Line(Front..In_Length)) );
	       else
	         TIO.Put_Line(Narrow_Out, In_Line(Front..In_Length) );
	       end if;
	       exit Line;
	     else
	       -- output the "normal" stuff up to the bracket
	       if Output_Mode = Wide then
	         WIO.Put(Wide_Out, Make_Wide(In_Line(Front..Open_Bracket-1)) );
	       else
	         TIO.Put(Narrow_Out, In_Line(Front..Open_Bracket-1) );
	       end if;

	       -- point beyond the closing bracket
	       Front := Close_Bracket +2;

	       -- output the translated hexadecimal character
	       if Output_Mode = Wide then
	         WIO.Put(Wide_Out,
	              	    To_Wide( In_Line(Open_Bracket+2..Close_Bracket-1) ));
	       else
	         TIO.Put(Narrow_Out,
		                    To_Ch( In_Line(Open_Bracket+2..Close_Bracket-1)) );
	       end if;
     	end if;
      end loop Line;

    end loop File;
    
    Close_Files;
  exception
    when others =>
      Ada.Text_IO.Put_Line("Error in processing " & Input_File_Name);
      raise;
  end Process;

begin

  Output_Mode := Wide;
  Process( Impdef.Wide_Character_Test );

  Output_Mode := Narrow;
  Process( Impdef.Upper_Latin_Test );

end WideChr;
